package com.ezandroid.library.image.ext.core.display.blur;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @see JavaBlurProcess Blur using the NDK and native code.
 */
public class NativeBlurProcess implements BlurProcess {

    private static final int EXECUTOR_THREADS = Runtime.getRuntime().availableProcessors();
    private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(EXECUTOR_THREADS);

    private static native void functionToBlur(Bitmap bitmapOut, int radius, int threadCount,
                                              int threadIndex, int round);

    private JavaBlurProcess mJavaBlurProcess = new JavaBlurProcess();
    private static boolean mUseJavaBlurProcess;

    static {
        try {
            System.loadLibrary("blur");
            mUseJavaBlurProcess = false;
        } catch (UnsatisfiedLinkError e) {
            e.printStackTrace();
            mUseJavaBlurProcess = true;
        }
    }

    @Override
    public Bitmap blur(Bitmap original, float radius) {
        if (mUseJavaBlurProcess) {
            return mJavaBlurProcess.blur(original, radius);
        } else {
            Bitmap bitmapOut = original.copy(Config.ARGB_8888, true);

            int cores = EXECUTOR_THREADS;

            ArrayList<NativeTask> horizontal = new ArrayList<NativeTask>(cores);
            ArrayList<NativeTask> vertical = new ArrayList<NativeTask>(cores);
            for (int i = 0; i < cores; i++) {
                horizontal.add(new NativeTask(bitmapOut, (int) radius, cores, i, 1));
                vertical.add(new NativeTask(bitmapOut, (int) radius, cores, i, 2));
            }

            try {
                EXECUTOR.invokeAll(horizontal);
            } catch (InterruptedException e) {
                return bitmapOut;
            }

            try {
                EXECUTOR.invokeAll(vertical);
            } catch (InterruptedException e) {
                return bitmapOut;
            }
            return bitmapOut;
        }
    }

    private static class NativeTask implements Callable<Void> {
        private final Bitmap _bitmapOut;
        private final int _radius;
        private final int _totalCores;
        private final int _coreIndex;
        private final int _round;

        public NativeTask(Bitmap bitmapOut, int radius, int totalCores, int coreIndex, int round) {
            _bitmapOut = bitmapOut;
            _radius = radius;
            _totalCores = totalCores;
            _coreIndex = coreIndex;
            _round = round;
        }

        @Override
        public Void call() throws Exception {
            functionToBlur(_bitmapOut, _radius, _totalCores, _coreIndex, _round);
            return null;
        }
    }
}
